﻿using System.Diagnostics;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Extended.NetRouting.Test
{
    /// <summary>
    /// This tests a simple way to use the library. Only strings are used to define nodes.
    /// </summary>
    [TestClass]
    public class SimpleTest
    {
        private static IRouteProvider routeProvider;

        [ClassInitialize]
        public static void MyClassInitialize(TestContext testContext)
        {
            // -------------------------------------------------------------------------------------
            // see attached diagram (.vsd or .png) for graphical representation of this sample network
            // -------------------------------------------------------------------------------------
            var memoryRouteProvider = new MemoryRouteProvider();
            memoryRouteProvider.Add("A", "B");
            memoryRouteProvider.Add("C", "H");
            memoryRouteProvider.Add("D", "E");
            memoryRouteProvider.Add("I", "F");
            memoryRouteProvider.Add("F", "G");
            memoryRouteProvider.Add("G", "I");
            memoryRouteProvider.Add("B", "C", twoWay: true);            // this is two way road
            memoryRouteProvider.Add("C", "D", twoWay: true);            // this is two way road
            memoryRouteProvider.Add("B", "I", length: 5, tag: "alt1");  // there are two routes from B to I so we have to tag this one
            memoryRouteProvider.Add("B", "I", length: 1, tag: "alt2");  // there are two routes from B to I so we have to tag this one
            memoryRouteProvider.Add("I", "E", length: 6);               // route with length equal to 6
            memoryRouteProvider.Add("G", "G");                          // route that begins and ends to the same spot

            routeProvider = memoryRouteProvider;
        }

        [TestMethod]
        public void ComplexTest()
        {
            // get all paths
            var paths = routeProvider.GetPaths("A", "E").ToList();
            Assert.AreEqual(3, paths.Count);

#if DEBUG
            Assert.AreEqual(10, Network.RouteVisitor.ExhaustedPaths);
#endif

            // debug write results
            foreach (var path in paths) Debug.WriteLine(path.ToNodeString(".") + " Length: " + path.Length);

            // get shortest path
            var shortestPath = routeProvider.GetShortestPath("A", "E");
            Assert.AreEqual(4, shortestPath.Length);
            Assert.AreEqual("A.B.C.D.E", shortestPath.ToNodeString("."));

#if DEBUG
            // assert the number of paths searched. number when using GetShortestPath should be smaller
            // than when using GetPaths, which searches all available paths
            Assert.AreEqual(6, Network.RouteVisitor.ExhaustedPaths);
#endif
        }

        [TestMethod]
        public void BidirectionalPath()
        {
            var shortestPath = routeProvider.GetShortestPath("D", "B");
            Assert.AreEqual(2, shortestPath.Length);
            Assert.AreEqual("D.C.B", shortestPath.ToNodeString("."));

            shortestPath = routeProvider.GetShortestPath("B", "D");
            Assert.AreEqual(2, shortestPath.Length);
            Assert.AreEqual("B.C.D", shortestPath.ToNodeString("."));
        }

        [TestMethod]
        public void SingleRoutePathTest()
        {
            var paths = routeProvider.GetPaths("I", "F").ToList();
            Assert.AreEqual(1, paths.Count);

            var shortestPath = routeProvider.GetShortestPath("I", "F");
            Assert.AreEqual("I.F", shortestPath.ToNodeString("."));
        }

        [TestMethod]
        public void PathInLoop()
        {
            var paths = routeProvider.GetPaths("I", "G").ToList();
            Assert.AreEqual(1, paths.Count);

            var shortestPath = routeProvider.GetShortestPath("I", "G");
            Assert.AreEqual("I.F.G", shortestPath.ToNodeString("."));
        }

        [TestMethod]
        public void NoPathTest()
        {
            var paths = routeProvider.GetPaths("I", "H").ToList();
            Assert.AreEqual(0, paths.Count);

            var shortestPath = routeProvider.GetShortestPath("I", "H");
            Assert.AreEqual(null, shortestPath);
        }

        [TestMethod]
        public void PathToStringTest()
        {
            // prepare a test path
            var path = new Path();
            path.Add(new Route("A", "B"));
            path.Add(new Route("B", "C"));
            path.Add(new Route("C", "D"));
            path.Add(new Route("D", "E"));

            // assert
            Assert.AreEqual("A.B.C.D.E", path.ToNodeString(".", true, true));
            Assert.AreEqual("A.B.C.D", path.ToNodeString(".", true, false));
            Assert.AreEqual("B.C.D.E", path.ToNodeString(".", false, true));
            Assert.AreEqual("B.C.D", path.ToNodeString(".", false, false));
        }
    }
}
